package com.violet.gateway.auth;

import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

/**
 * @Author: wqf
 * @Date: 2024/09/10
 * @Description: jwt认证管理器，主要作用是对携带过来的token进行校验，比如过期时间，加密方式等
 * 一旦token校验通过，则交给鉴权管理器进行鉴权
 */
@Slf4j
@Component
public class CustomAuthenticationManager implements ReactiveAuthenticationManager {

    private final TokenStore tokenStore;

    public CustomAuthenticationManager(TokenStore tokenStore) {
        this.tokenStore = tokenStore;
    }


    @Override
    public Mono<Authentication> authenticate(Authentication authentication) {

        if (!(authentication instanceof BearerTokenAuthenticationToken)) {
            return Mono.error(new IllegalArgumentException("Unsupported authentication type"));
        }
        BearerTokenAuthenticationToken bearerTokenAuthentication = (BearerTokenAuthenticationToken) authentication;
        String accessToken = bearerTokenAuthentication.getToken();
        //读取令牌
        OAuth2AccessToken oAuth2AccessToken = this.tokenStore.readAccessToken(accessToken);
        //根据access_token从数据库获取不到OAuth2AccessToken
        if (oAuth2AccessToken == null) {
            return Mono.error(new InvalidTokenException("无效token！"));
        } else if (oAuth2AccessToken.isExpired()) {
            return Mono.error(new InvalidTokenException("token已过期！"));
        }
        //解析令牌携带的用户身份信息 用户名,权限等
        OAuth2Authentication oAuth2Authentication = this.tokenStore.readAuthentication(accessToken);
        if (oAuth2Authentication == null) {
            return Mono.error(new InvalidTokenException("无效token！"));
        } else {
            return Mono.just(oAuth2Authentication);
        }
    }
}
